#include "lib.h"

#include "rlguts.h"
#include "amerguts.h"
#include "euroguts.h"
#include "rlround.h"

#ifdef FORCED_ROULETTE
#include "opts.h"
#include "odbc.h"
#endif

#define NUMGUTS	2

static RouletteGuts* sGuts[] =
{
	new AmericanRouletteGuts(),
	new EuropeanRouletteGuts()
};

RouletteGuts*
RouletteGuts::getGuts(uint8 which)
{
	return (RouletteGuts*)(which < NUMGUTS ? sGuts[which] : 0);
}

#ifdef FORCED_ROULETTE

#pragma message ("****** WARNING *******************************************")
#pragma message ("         YOU ARE COMPILING FORCED ROULETTE!!!!            ")
#pragma message ("      Please ensure you do not add this to release code!!!")
#pragma message ("**********************************************************")

static const uint8 SPIN_MIN     = 0;    // Min spin value in Roulette
static const uint8 SPIN_MAX_AME = 37;   // Max spin value in American Roulette
static const uint8 SPIN_MAX_EUR = 36;   // Max spin value in European Roulette
static const uint8 SPIN_INVALID = 0xFF; // Invalid spin value

RouletteForcedGuts::RouletteForcedGuts(uint8 tableId)
{
	reset();
	
	// Set range of valid values
	range.min = SPIN_MIN;
	range.max = (tableId == 0) ? SPIN_MAX_AME : SPIN_MAX_EUR;	
}

RouletteForcedGuts::~RouletteForcedGuts()
{
	clear();
}

// CSN-12125 - Load forced spins from database only if Testing is enabled
bool8 RouletteForcedGuts::load(uint8 tableId, String pid)
{
	bool8 isLoaded = false;

	// Clear forced spins if there were loaded previously	
	if (!isEmpty())
		clear();

	if (ServerOpts::bAllowTesting)
	{
		// Create new database pool
		ODBCPool* pool = new ODBCPool();
		if (pool)
		{
			// Initialize the database pool
			if (pool->init())
			{
				ODBCConnection* conn = pool->open(ServerOpts::dbdsn, ServerOpts::dblogin, ServerOpts::dbpasswd);
				if (conn)
				{
					ODBCQuery* query = conn->query();
					if (query)
					{
						query->define("exec QATestTools_NonProd.dbo.pub_getRouletteForcedSpins ");
						query->addParam(pid);
						query->addParam(tableId);
						
						if (query->exec())
						{
							if (query->getRow())
							{
								String data;

								if (query->getData(1, &data))
								{					
									int32 length = data.getLength();
									
									// Check that we received an even number of digits			
									if (length > 0 && length % 2 == 0)
									{
										total = length / 2; 
										spins = new uint8[total];
										int j = 0;
										
										// Populate the spin list				
										for (uint8 i = 0; i < total; i++)
										{
											spins[i] = encodeSpin(data.substring(j, 2));
											j += 2;
											
											// Check that the spin value is correct					
											if (spins[i] == SPIN_INVALID)
											{
												total--; // Reduce the spin list size
												i--;
											}
										}

										// Return true only if one spin at least was loaded							
										if (total > 0)
										{
											isLoaded = true;
											current  = 0 ;

											String loaded, l;
											for (int i = 0; i < total; i++)
											{
												l.sprintf("%d ", spins[i]);
												loaded += l;
											}

											DEBUGMSG(("Forced spins loaded. tableId=%d pid=%S spins=%S",
											         tableId, (const wchar_t*)pid, (const wchar_t*)loaded));
										}
									}
								}
							}
						}
						
						delete query;
					}

					delete conn;
				}
			}

			delete pool;
		}
	}

	return isLoaded;
}

uint8 RouletteForcedGuts::spin()
{
	uint8 spin = SPIN_INVALID;
	
	if (!isEmpty())
	{
		spin = spins[current++];

		if (current == total)
			current = 0;
	}

	return spin;	
}

bool8 RouletteForcedGuts::isEmpty()
{
	return (bool8)(total == 0);
}

void RouletteForcedGuts::clear()
{
	delete [] spins;
	reset();
}

void RouletteForcedGuts::reset()
{
	spins   = (uint8*)0;
	total   = 0;
	current = -1;
}

uint8 RouletteForcedGuts::encodeSpin(String decoded)
{
	uint8 spin = (uint8)(decoded.toUInt16());
	
	if (spin < range.min || spin > range.max)
		spin = SPIN_INVALID;
	
	return spin;
}

#endif // FORCED_ROULETTE

//////////////////////////////////////////////////////////////////////////////
// CleaupGuts cleans sGuts[] to avoid false reports of memory leaks.
//////////////////////////////////////////////////////////////////////////////
static 
class CleanupGuts
{
public:
	~CleanupGuts()
	{
		for (int i = 0; i < NUMGUTS; ++i )
		{
			delete sGuts[i];
			sGuts[i] = 0;
		}
	}
} autoRunCleanupGutsOnExit;
